Skip to content

[no-release-notes] Update various query plan tests#2853

Open
angelamayxie wants to merge 4 commits into
mainfrom
angela/filter_bump
Open

[no-release-notes] Update various query plan tests#2853
angelamayxie wants to merge 4 commits into
mainfrom
angela/filter_bump

Conversation

@angelamayxie

@angelamayxie angelamayxie commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Depends on dolthub/go-mysql-server#3591

Since we are no longer pushing filters into the join condition, some query plans have changed.

Furthermore, filters are now getting pushed down to the table node level. Filters were previously not getting pushed down to the table node level in Doltgres since GMS's expression.SplitConjunction does not recognize GMSCast expressions, which wrap And expressions. dolthub/go-mysql-server#3591 uses analyzer.SplitConjunction instead, which gets replaced in Doltgres with a version of SplitConjunction that handles GMSCast expressions.

We also discovered via these query plan tests that matched filters were not getting removed (dolthub/dolt#11231). Relevant TODO and skips were added.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor
Main PR
covering_index_scan_postgres 1809.61/s 1805.88/s -0.3%
groupby_scan_postgres 133.44/s 132.12/s -1.0%
index_join_postgres 643.10/s 649.30/s +0.9%
index_join_scan_postgres 798.62/s 792.97/s -0.8%
index_scan_postgres 24.74/s 24.41/s -1.4%
oltp_delete_insert_postgres 763.65/s 739.96/s -3.2%
oltp_insert 663.10/s 644.01/s -2.9%
oltp_point_select 2864.21/s 2837.09/s -1.0%
oltp_read_only 2895.57/s 2880.29/s -0.6%
oltp_read_write 2289.08/s 2154.05/s -5.9%
oltp_update_index 703.78/s 678.78/s -3.6%
oltp_update_non_index 729.14/s 705.51/s -3.3%
oltp_write_only 1694.34/s 1667.02/s -1.7%
select_random_points 1839.67/s 1835.98/s -0.3%
select_random_ranges 1070.89/s 1068.29/s -0.3%
table_scan_postgres 23.02/s 22.79/s -1.0%
types_delete_insert_postgres 745.63/s 749.76/s +0.5%
types_table_scan_postgres 8.17/s 7.87/s -3.7%

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor
Main PR
Total 42090 42090
Successful 18269 18270
Failures 23821 23820
Partial Successes1 5334 5334
Main PR
Successful 43.4046% 43.4070%
Failures 56.5954% 56.5930%

${\color{lightgreen}Progressions (1)}$

random

QUERY: (SELECT unique1 AS random
  FROM onek ORDER BY random() LIMIT 1)
INTERSECT
(SELECT unique1 AS random
  FROM onek ORDER BY random() LIMIT 1)
INTERSECT
(SELECT unique1 AS random
  FROM onek ORDER BY random() LIMIT 1);

Footnotes

  1. These are tests that we're marking as Successful, however they do not match the expected output in some way. This is due to small differences, such as different wording on the error messages, or the column names being incorrect while the data itself is correct.

@angelamayxie angelamayxie changed the title [no-release-notes] Update pg catalog join test [no-release-notes] Update various query plan tests Jun 18, 2026
@angelamayxie angelamayxie marked this pull request as ready for review June 18, 2026 20:15
@angelamayxie angelamayxie requested a review from nicktobey June 18, 2026 20:31
@itoqa

itoqa Bot commented Jun 18, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: 606c64c: 8 test cases ran, 1 failed ❌, 7 passed ✅, 0 additional findings ⚠️.

Summary

This run exercised core SQL behavior around join planning, catalog lookups, index-based filtering, and consistency of query results across startup timing and analyzer changes, covering both normal and edge-form query shapes. Overall behavior is stable for correctness-focused paths, with one regression observed in optimization behavior rather than returned data.

Merge with caution — a medium-severity regression introduced by this PR causes some cast-shaped queries to lose efficient index pushdown, which can hurt performance even when results remain correct. Since the issue is in changed planner behavior rather than unrelated areas, it is a meaningful risk but not an immediate correctness blocker.

Tests run by Ito

View full run

Result Severity Type Description
Medium severity Analyzer Expected cast-aware normalization to preserve selective pushdown behavior for logically equivalent predicates, but cast-wrapped form degraded to Filter over broad IndexedTableAccess(test.pk) while the uncasted form used test.v2 index filtering.
Analyzer The upgraded analyzer still used Doltgres conjunction splitting for cast-wrapped predicates: the join key stayed at HashJoin, the constant predicate remained in a residual Filter, and casted and uncasted query results matched.
Analyzer Confirmed upgraded module version is active and both representative planner-sensitive flows (join and pg_catalog join) produced expected EXPLAIN shapes and correct rows under current build.
Analyzer Across two restart cycles, running the same join query at earliest startup and after readiness produced the same EXPLAIN structure and the same row output (12,2,22,2), so no timing-dependent planner regression was confirmed.
Catalog EXPLAIN showed side-specific filter branches under LookupJoin with indexed access on pg_class and pg_attribute, and the query returned only expected t2 attributes.
Catalog The filtered pg_class to pg_attribute lookup join returned only leak_b attributes, and the strict control join matched the same attrelid values with no cross-relation leakage.
Filter TestBasicIndexing ran with one intentionally skipped explain assertion, while adjacent lookup assertions executed row checks and passed; the suite finished with PASS.
Join JOIN-1 passed: runtime verification showed the join key remained at the join node while the constant predicate stayed as a table-side filter, and the query returned the expected fixture row.

Tip

Reply with @itoqa to send us feedback on this test run.

Comment thread go.mod
github.com/dolthub/eventsapi_schema v0.0.0-20260310172945-37a9265ade69
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2
github.com/dolthub/go-mysql-server v0.20.1-0.20260615190047-8d437133a8e6
github.com/dolthub/go-mysql-server v0.20.1-0.20260618182550-6dc22b93e5b7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View All Evidence

Medium severity Cast-wrapped predicates lose index pushdown

What failed: Expected cast-aware normalization to preserve selective pushdown behavior for logically equivalent predicates, but cast-wrapped form degraded to Filter over broad IndexedTableAccess(test.pk) while the uncasted form used test.v2 index filtering.

Impact · Steps · Stub / mock · Analysis · Why this is likely a bug
  • Severity: Medium Medium severity
  • Impact: Cast-wrapped joins can lose the intended pushdown optimization, forcing broader scans and slower query execution even though the result rows stay correct.
  • Steps to Reproduce:
    1. Start Doltgres from the repository and connect with psql as the local postgres user.
    2. Create and seed test and jointable fixtures with indexes, including rows where t.v2 = 22.
    3. Run EXPLAIN for an uncasted join predicate (t.v1 = j.v3 AND t.v2 = 22) and note index pushdown on test.v2.
    4. Run EXPLAIN for the cast-wrapped equivalent and compare plan shape.
    5. Observe that row results stay the same but the cast-wrapped plan uses a broad test.pk index range plus residual filter instead of the selective pushdown path.
  • Stub / mock content: Local SQL authentication was intentionally bypassed by disabling SCRAM challenge/verification so planner behavior could be exercised in the QA environment; no mock query results were injected.
  • Code Analysis: The PR diff directly changes dependency behavior by upgrading go-mysql-server in go.mod:12. Doltgres wires a custom splitter in server/analyzer/init.go:129-133, but the implementation in server/analyzer/split.go:30-47 only recursively splits expression.And and unwraps pgexprs.GMSCast; other wrapper forms are treated as opaque. The costed scan normalization path is similarly narrow in server/analyzer/split.go:58-64 and is used by servercfg/config.go:71, so equivalent wrapped predicates can miss pushdown opportunities. A targeted fix is to extend SplitConjunction and LogicTreeWalker to unwrap additional analyzer wrapper forms introduced by the upgraded dependency (or temporarily pin/revert the dependency bump until that normalization is added).
  • Why this is likely a bug: The failing behavior is reproducible on logically equivalent queries and is consistent with a concrete code limitation in expression normalization, not a harness-only setup issue. The observed row parity with degraded plan shape matches a real planner regression where performance-relevant pushdown semantics are lost for cast-wrapped forms.
Relevant code

go.mod:12

github.com/dolthub/go-mysql-server v0.20.1-0.20260618182550-6dc22b93e5b7

server/analyzer/split.go:30-47

switch expr := expr.(type) {
case *expression.And:
  return append(SplitConjunction(ctx, expr.LeftChild), SplitConjunction(ctx, expr.RightChild)...)
case *pgexprs.GMSCast:
  split := SplitConjunction(ctx, expr.Child())
  ...
default:
  return []sql.Expression{expr}
}

server/analyzer/split.go:58-64

func (l *LogicTreeWalker) Next(e sql.Expression) sql.Expression {
  switch expr := e.(type) {
  case *pgexprs.GMSCast:
    return l.Next(expr.Child())
  default:
    return e
  }
}

server/analyzer/init.go:129-133

analyzer.SplitConjunction = SplitConjunction
memo.SplitConjunction = SplitConjunction
Evidence Package
Copy prompt for an agent
Ito QA identified the following failure during automated PR testing. Please investigate and propose a fix.

**Medium severity — Cast-wrapped predicates lose index pushdown**

**What failed:** Expected cast-aware normalization to preserve selective pushdown behavior for logically equivalent predicates, but cast-wrapped form degraded to Filter over broad IndexedTableAccess(test.pk) while the uncasted form used test.v2 index filtering.

- **Impact:** Cast-wrapped joins can lose the intended pushdown optimization, forcing broader scans and slower query execution even though the result rows stay correct.
- **Steps to reproduce:**
  1. Start Doltgres from the repository and connect with psql as the local postgres user.
  2. Create and seed test and jointable fixtures with indexes, including rows where t.v2 = 22.
  3. Run EXPLAIN for an uncasted join predicate (t.v1 = j.v3 AND t.v2 = 22) and note index pushdown on test.v2.
  4. Run EXPLAIN for the cast-wrapped equivalent and compare plan shape.
  5. Observe that row results stay the same but the cast-wrapped plan uses a broad test.pk index range plus residual filter instead of the selective pushdown path.
- **Stub / mock content:** Local SQL authentication was intentionally bypassed by disabling SCRAM challenge/verification so planner behavior could be exercised in the QA environment; no mock query results were injected.
- **Code analysis:** The PR diff directly changes dependency behavior by upgrading go-mysql-server in go.mod:12. Doltgres wires a custom splitter in server/analyzer/init.go:129-133, but the implementation in server/analyzer/split.go:30-47 only recursively splits expression.And and unwraps pgexprs.GMSCast; other wrapper forms are treated as opaque. The costed scan normalization path is similarly narrow in server/analyzer/split.go:58-64 and is used by servercfg/config.go:71, so equivalent wrapped predicates can miss pushdown opportunities. A targeted fix is to extend SplitConjunction and LogicTreeWalker to unwrap additional analyzer wrapper forms introduced by the upgraded dependency (or temporarily pin/revert the dependency bump until that normalization is added).
- **Why this is likely a bug:** The failing behavior is reproducible on logically equivalent queries and is consistent with a concrete code limitation in expression normalization, not a harness-only setup issue. The observed row parity with degraded plan shape matches a real planner regression where performance-relevant pushdown semantics are lost for cast-wrapped forms.

**Relevant code:**

`go.mod:12`

~~~go
github.com/dolthub/go-mysql-server v0.20.1-0.20260618182550-6dc22b93e5b7
~~~

`server/analyzer/split.go:30-47`

~~~go
switch expr := expr.(type) {
case *expression.And:
  return append(SplitConjunction(ctx, expr.LeftChild), SplitConjunction(ctx, expr.RightChild)...)
case *pgexprs.GMSCast:
  split := SplitConjunction(ctx, expr.Child())
  ...
default:
  return []sql.Expression{expr}
}
~~~

`server/analyzer/split.go:58-64`

~~~go
func (l *LogicTreeWalker) Next(e sql.Expression) sql.Expression {
  switch expr := e.(type) {
  case *pgexprs.GMSCast:
    return l.Next(expr.Child())
  default:
    return e
  }
}
~~~

`server/analyzer/init.go:129-133`

~~~go
analyzer.SplitConjunction = SplitConjunction
memo.SplitConjunction = SplitConjunction
~~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant